/*
 * @Author: 刘佳欢 2173558681@qq.com
 * @Date: 2025-06-27 10:17:40
 * @LastEditors: 刘佳欢 2173558681@qq.com
 * @LastEditTime: 2025-06-29 11:11:19
 * @FilePath: \test\Calculator.java
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import javax.swing.JButton;
import javax.swing.Timer;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Dimension;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.awt.Color;  // 用于处理颜色
import javax.swing.JDialog;  // 对话框组件
import javax.swing.JTextField;  // 文本输入框
import javax.swing.Timer;  // 定时器（可选，用于自动恢复输入框显示）
import javax.swing.JTextArea;
import java.io.File;
import javax.sound.sampled.*;
import java.io.IOException;

//继承JFrame为了直接复用swing框架中窗口管理的能力
//为了子类可以直接调用JFrame public的方法
//ApplicationListener是java中事件处理的核心部分
//为了建立计算器组件和用户操作之间的响应机制
public class Calculator extends JFrame implements ActionListener{
    private Clip backgroundMusic;//调用Clip接口实现背景音乐的播放
    private Timer clockTimer; // 用于实时更新时间的定时器
    private boolean isShowingTime = false; // 标记是否正在显示时间
     // 加载并自动播放背景音乐
    private void loadAndPlayBackgroundMusic() {
        try {
            File musicFile = new File("background_music.wav"); 
            if (musicFile.exists()) {
            // 获取音频输入流
                AudioInputStream audioInput = AudioSystem.getAudioInputStream(musicFile);
                // 获取音频Clip对象
                backgroundMusic = AudioSystem.getClip();
                //打开音频流
                backgroundMusic.loop(Clip.LOOP_CONTINUOUSLY); 
                // 循环播放
                backgroundMusic.open(audioInput);
                backgroundMusic.start(); // 自动开始播放
            } else {
                System.err.println("音乐文件未找到: " + musicFile.getAbsolutePath());
                field.setText("背景音乐文件未找到");
                Timer timer = new Timer(2000, e -> field.setText(""));
                timer.setRepeats(false);
                timer.start();
            }
        } catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
             // 处理加载音乐时可能出现的异常
            e.printStackTrace();
            field.setText("加载音乐出错");
            Timer timer = new Timer(2000, event -> field.setText(""));
            timer.setRepeats(false);//设置定时器只执行一次
            timer.start();
        }
    }
    //声明界面组件
    //上下两个容器面板，上面是文本框区域，下面是按钮区域
    private JPanel north,center,south;
    //文本框 显示计算过程，结果或者日期时间
    private JTextField field;
    //按钮
    private JButton[] btns;
    private boolean isDarkMode = false;
    private JTextArea historyArea;

    //初始化窗口-构造器 构造方法 无参构造器
    public Calculator(){
        //设置窗口title
        setTitle("计算器");
        //设置窗口大小
        setSize(700,700);
        //设置窗口关闭时的程序
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        //设置窗口居中显示
        setLocationRelativeTo(null);
        //初始化界面组件的方法
        initComponent();
        loadAndPlayBackgroundMusic(); // 加载并自动播放背景音乐
        //设置窗口显示
        setVisible(true);
         // 初始化时钟定时器，每秒更新一次
        clockTimer = new Timer(1000, e -> {
            if (isShowingTime) {
                updateCurrentTime();
            }
        });
        clockTimer.start();// 启动定时器
    }
      // 更新时间显示
    private void updateCurrentTime() { 
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 将格式化后的时间显示在文本框中
        field.setText(now.format(formatter));
    }
    
    // 显示/隐藏时间
    private void showCurrentTime() {
        isShowingTime = !isShowingTime; // 切换状态
        
        if (isShowingTime) {
            updateCurrentTime(); // 立即更新时间
        } else {
            field.setText(""); // 清空显示
        }
    }
    //初始化界面组件
    private void initComponent(){
        //创建面板容器
        //容器面板 文本框区域
        north=new JPanel();
        //容器面板 按钮区域
        center=new JPanel();
        south = new JPanel();
        //文本框 显示计算过程，结果或日期时间
        field=new JTextField();
        historyArea=new JTextArea();
        //设置输入框大小 首选尺寸
        field.setPreferredSize(new Dimension(700,150));
        //禁用文字输入 禁止通过电脑键盘输入编辑
        field.setEditable(false);
        // 设置输入框中文字大小
        field.setFont(new Font("SansSerif",Font.BOLD,35));
       // 按钮文本内容
        String[] str=new String[]{
            "7","8","9","+",
            "4","5","6","-",
            "1","2","3","×",
            "0",".","=","÷",
            "C","B","T","S"

        };
    
        //按钮数组
        btns=new JButton[str.length];
        for(int i=0;i<btns.length;i++){
            btns[i]=new JButton(str[i]);
            btns[i].setFont(new Font("SansSerif",Font.BOLD,25));
        }
        //将组件放在窗口中
        //设置布局管理器
        //north顶部面板 使用BorderLayout边界布局
        north.setLayout(new BorderLayout());
        //center中间面板 5行4列 网格布局
        center.setLayout(new GridLayout(5,4));
        //组件设置
        //field 文本框 添加到north顶部面板 使用 BorderLayout 居中
        //btns 按钮 添加到center面板 使用BorderLayout居中
        north.add(field,BorderLayout.CENTER);
        south.setLayout(new BorderLayout());
        //btn 按钮 添加到center面板 增强for循环
        for(JButton btn:btns){
            // 通过遍历将所有按钮添加到 center 面板
            center.add(btn); 
        }
        //将north顶部面板添加到窗口中
        add(north,BorderLayout.NORTH);
        //将center面板添加到窗口中
        add(center);
        //绑定按钮监听事件
        for(JButton btn:btns){
            btn.addActionListener(this);//this代表当前对象实例
        }
    }
    
    //处理按键文本
    private void setBtnText(String text){
        String currentText = field.getText();
        //System.out.println("Text length:"+field.getText().length());
        switch(text){
         case "C":
            // 清空文本框
            field.setText("");
            //System.out.println("C");
            break;
         case "B":
            //退格功能
            //1.获取输入框的内容
            String numText=field.getText();
            //两种情况(有内容，无内容)isEmpty()
            if(numText.length()!=0){
                //输入框内容不能为空
               // System.out.println("numText");
               //numText的长度-1
               String lastText=numText.substring(0,numText.length()-1);
               //将截取后的文本设置到输入框
               field.setText(lastText);
            }else{
               // System.out.println("输入框内容为空");
            }
             //System.out.println("B");
             break;
        case "T" :
            showCurrentTime();
            break;
        case "S" :
             isDarkMode = !isDarkMode;
    updateTheme();
    field.setText(isDarkMode ? "深色模式" : "浅色模式");
    
    // 1秒后恢复输入框显示
    Timer timer = new Timer(1000, e -> {
        // 检查文本框内容是否不符合数学表达式格式（包含非数字/运算符字符）
        // 正则表达式
        if (!field.getText().matches("^[0-9.+-×÷=]+$")) {
            field.setText("");
        }
    });
    timer.setRepeats(false);
    timer.start();
            break;
         case "=" :
            calculate();
            break;
         case ".":
                if(currentText.isEmpty()){
                    field.setText("0.");
                } else {
                    char lastChar = currentText.charAt(currentText.length()-1);
                    // 防止小数点连续出现
                    if(lastChar != '.') {
                        // 检查当前数字是否已有小数点
                        String[] parts = currentText.split("[+\\-×÷]");
                        String lastNumber = parts[parts.length - 1];
                        if (!lastNumber.contains(".")) {
                            field.setText(currentText + ".");
                        }
                    }
                 }
                  break;  
                
            case "+":
            case "-":
            case "×":
            case "÷":
                // 防止操作符在数字前出现
                if(!currentText.isEmpty()) {
                    char lastChar = currentText.charAt(currentText.length()-1);
                    // 防止连续操作符
                    if(!isOperator(lastChar)) {
                        field.setText(currentText + text);
                    } else {
                        // 替换最后一个操作符
                        field.setText(currentText.substring(0, currentText.length()-1) + text);
                    }
                }
                break;
        default:
        // 按下数字键或者运算符 要把文字放到输入框中
        String oldText=field.getText();//1
         // 如果输入框是0，直接替换为新输入的数字
        if (oldText.equals("0") && isNumeric(text)) {
            field.setText(text);
        } else {
            field.setText(oldText+text);
        }
        if (currentText.equals("0")) {
                    field.setText(text);
                } else {
                    field.setText(currentText+text);
                }
        // 如果之前输入框中有文字 做拼接
        //field.setText(oldText+text);//12
        break;
        }
    }
    private void updateTheme() {
    Color bgColor, fgColor, btnBgColor, btnFgColor;
    
    if (isDarkMode) {
        bgColor = Color.DARK_GRAY;
        fgColor = Color.WHITE;
        btnBgColor = Color.GRAY;
        btnFgColor = Color.WHITE;
    } else {
        bgColor = Color.WHITE;
        fgColor = Color.BLACK;
        btnBgColor = new Color(230, 230, 230);
        btnFgColor = Color.BLACK;
    }
    
    getContentPane().setBackground(bgColor);
    field.setBackground(bgColor);
    field.setForeground(fgColor);
    historyArea.setBackground(bgColor);
    historyArea.setForeground(fgColor);
    
    for (JButton btn : btns) {
        btn.setBackground(btnBgColor);
        btn.setForeground(btnFgColor);
    }
}
    // 判断字符是否为运算符
    private boolean isOperator(char c) {
        return c == '+' || c == '-' || c == '×' || c == '÷';
    }
    
    // 判断字符串是否为数字
    private boolean isNumeric(String str) {
        try {
            Double.parseDouble(str);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }
    
    private void calculate(){
            //用户输入1+1
            //如果表达式中有×÷要替换为*/
           String expression= field.getText();
           // 将×÷替换为*/
            expression = expression.replace("×", "*");
            expression = expression.replace("÷", "/");
             // 移除表达式末尾的操作符
        if(!expression.isEmpty() && isOperator(expression.charAt(expression.length()-1))) {
            expression = expression.substring(0, expression.length()-1);
        }
            // 执行计算操作,使用js计算引擎
            ScriptEngineManager manager=new ScriptEngineManager();
            //初始化计算引擎 使用javascript解析数学表达式
            ScriptEngine engine=manager.getEngineByName("javascript");
            try{
            //开始计算 计算过程可能出现异常 这里需要处理异常
            Object result=engine.eval(expression);
            field.setText(result.toString());
            }catch (ScriptException e){
                field.setText("运算错误");
                e.printStackTrace();
            }
    
            // 将结果展示到文本框
            //field.setText();
    }
    //实现addActionListener接口中抽象方法 处理事件
    @Override
    public void actionPerformed(ActionEvent a){
//此处可以捕获ActionListener监听的事件
        //System.out.println(a.getSource());
        //获取被点击的按钮
        Object source=a.getSource();
        // 检查是否是按钮组件
        if(source instanceof JButton){
            // 类型转换
            JButton btn=(JButton) source;
            // 获取按钮文本
            String text=btn.getText();
            //处理对应按键文字
            setBtnText(text);
        }

    }
    public static void main(String[] args){
        //System.out.println("hello,Calculator");
        //创建类的对象-线程不安全
        //new Calculator();
        // Java Swing 中用于安全创建和显示 GUI 组件的关键方法调用
        SwingUtilities.invokeLater(Calculator::new);

    } 
     // 添加窗口关闭时的音乐停止和停止定时器功能
    @Override
    public void dispose() {
        if (backgroundMusic != null) {
            backgroundMusic.stop();
            backgroundMusic.close();
        }
         if (clockTimer != null) {
            clockTimer.stop();
        }
        super.dispose();
    }
}

